package com.bandi.tharshesnows.persistence;

import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Map.Entry;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.bandi.tharshesnows.model.County;
import com.bandi.tharshesnows.model.Resort;
import com.bandi.tharshesnows.model.Location;
import com.bandi.tharshesnows.model.SkiTransport;
import com.bandi.tharshesnows.model.Skirun;
import com.bandi.tharshesnows.model.SkirunDifficulty;
import com.bandi.tharshesnows.model.SkirunStatus;
import com.bandi.tharshesnows.persistence.Metadata.LocalityMetadata;
import com.bandi.tharshesnows.persistence.Metadata.SkirunMetadata;

public class SkirunDAO {

  private Database database;

  SkirunDAO(Database database) {
    super();
    this.database = database;
  }

  public Skirun create(Skirun skirun) throws DAOException {
    try {
      SQLiteDatabase db = database.open();
      ContentValues values = new ContentValues();
      values.put(SkirunMetadata.LOCALITY_ID, skirun.getResort().get_id());
      values.put(SkirunMetadata.LOADED,skirun.isDownloaded()?1:0);// false
      values.put(SkirunMetadata.REMOTE_URL, skirun.getRemoteURL());
      values.put(SkirunMetadata.NAME, skirun.getName());
      values.put(SkirunMetadata.SKIRUNSTATUS, skirun.getSkirunStatus().name());
      skirun.set_id(db.insert(SkirunMetadata.TABLE_NAME, null, values));
      return skirun;
    }
    catch (Throwable t) {
      throw new DAOException("Failed to create skirun.", t);
    }
    finally {
      database.close();
    }
  }

  public Skirun get(String name, Resort locality) throws DAOException {
    try {
      SQLiteDatabase db = database.open();
      Cursor cursor = db.query(SkirunMetadata.TABLE_NAME, SkirunMetadata.COLUMNS, SkirunMetadata.NAME + " = '" + name
          + "' AND " + SkirunMetadata.LOCALITY_ID + " = " + locality.get_id(), null, null, null, null);
      if (cursor.moveToFirst()) {
        return map(cursor, locality);
      }
      else {
        return null;
      }
    }
    catch (Throwable t) {
      throw new DAOException("Failed to get skirun.", t);
    }
    finally {
      database.close();
    }
  }

  public Skirun get(long id, Resort locality) throws DAOException {
    try {
      SQLiteDatabase db = database.open();
      Cursor cursor = db.query(SkirunMetadata.TABLE_NAME, SkirunMetadata.COLUMNS, SkirunMetadata._ID + " = " + id,
          null, null, null, null);
      if (cursor.moveToFirst()) {
        return map(cursor, locality);
      }
      else {
        return null;
      }
    }
    catch (Throwable t) {
      throw new DAOException("Failed to get skirun.", t);
    }
    finally {
      database.close();
    }
  }

  public Skirun update(Skirun skirun) throws DAOException {
    try {
      SQLiteDatabase db = database.open();
      ContentValues values = new ContentValues();
      values.put(SkirunMetadata.LOADED, skirun.isDownloaded() ? 1 : 0);
      values.put(SkirunMetadata.SKIRUNSTATUS, skirun.getSkirunStatus().name());
      values.put(SkirunMetadata.CANONS, skirun.hasCanons() ? 1 : 0);
      values.put(SkirunMetadata.DESTINATION_ALT, skirun.getDestinationAltitude());
      values.put(SkirunMetadata.LENGTH, skirun.getLength());
      if (skirun.getDifficulty() != null) {
        values.put(SkirunMetadata.DIFFICULTY, skirun.getDifficulty().name());
      }
      values.put(SkirunMetadata.INCLINATION, skirun.getInclination());
      if (skirun.getLocation() != null) {
        values.put(SkirunMetadata.LATITUDE, "" + skirun.getLocation().getLatitude());
        values.put(SkirunMetadata.LONGITUDE, "" + skirun.getLocation().getLongitude());
        values.put(SkirunMetadata.MAP_IMG, skirun.getLocation().getStaticMapImagePath());
      }
      values.put(SkirunMetadata.METEO_URL, skirun.getMeteoURL());
      values.put(SkirunMetadata.NIGHTMODE, skirun.isNightmode() ? 1 : 0);
      values.put(SkirunMetadata.SCHEDULE, skirun.getSchedule());

      StringBuilder builder = new StringBuilder("");
      for (Entry<SkiTransport, Integer> entry : skirun.getSkiTransports().entrySet()) {
        builder.append(entry.getValue() + "x" + entry.getKey().name() + "|");
      }
      values.put(SkirunMetadata.SKI_TRANSPORTS, builder.toString());
      values.put(SkirunMetadata.SKIRUNSTATUS, skirun.getSkirunStatus().name());
      values.put(SkirunMetadata.SNOW_HEIGHT, skirun.getSnowHeight());
      values.put(SkirunMetadata.STARRED, skirun.isStarred() ? 1 : 0);
      values.put(SkirunMetadata.STARTING_ALT, skirun.getStartingAltitude());
      values.put(SkirunMetadata.OBSERVATIONS, skirun.getObservations());
      if (skirun.getUpdated() != null) {
        values.put(SkirunMetadata.UPDATED, skirun.getUpdated().getTime());
      }
      values.put(SkirunMetadata.WIDTH, skirun.getWidth());
      skirun.set_id(db.update(SkirunMetadata.TABLE_NAME, values, SkirunMetadata._ID + "=" + skirun.get_id(), null));
      return skirun;
    }
    catch (Throwable t) {
      throw new DAOException("Failed to create skirun.", t);
    }
    finally {
      database.close();
    }
  }

  public List<Skirun> getForLocality(Resort locality) throws DAOException {
    try {
      SQLiteDatabase db = database.open();
      List<Skirun> skiruns = new ArrayList<Skirun>();
      Cursor cursor = db.query(SkirunMetadata.TABLE_NAME, SkirunMetadata.COLUMNS, SkirunMetadata.LOCALITY_ID + "="
          + locality.get_id(), null, null, null, null);
      cursor.moveToFirst();
      if (cursor.moveToFirst()) {
        do {
          skiruns.add(map(cursor, locality));
        } while (cursor.moveToNext());
      }
      return skiruns;
    }
    catch (Throwable t) {
      throw new DAOException("Failed to get skiruns for: " + locality.getName(), t);
    }
    finally {
      database.close();
    }
  }

  private Skirun map(Cursor cursor, Resort locality) throws ParseException {
    Skirun skirun = new Skirun(locality);
    skirun.set_id(cursor.getLong(cursor.getColumnIndex(SkirunMetadata._ID)));
    skirun.setCanons(cursor.getInt(cursor.getColumnIndex(SkirunMetadata.CANONS)) == 1 ? true : false);
    skirun.setDestinationAltitude(cursor.getDouble(cursor.getColumnIndex(SkirunMetadata.DESTINATION_ALT)));
    String diff = cursor.getString(cursor.getColumnIndex(SkirunMetadata.DIFFICULTY));
    if (diff != null) {
      skirun.setDifficulty(SkirunDifficulty.valueOf(diff));
    }
    skirun.setInclination(cursor.getDouble(cursor.getColumnIndex(SkirunMetadata.INCLINATION)));
    skirun.setLength(cursor.getDouble(cursor.getColumnIndex(SkirunMetadata.LENGTH)));
    String lat = cursor.getString(cursor.getColumnIndex(SkirunMetadata.LATITUDE));
    String lon = cursor.getString(cursor.getColumnIndex(SkirunMetadata.LONGITUDE));
    if (lat != null && lon != null && lat.length() > 0 && lon.length() > 0) {
      skirun.setLocation(new Location(Double.parseDouble(lat), Double.parseDouble(lon)));
      skirun.getLocation().setStaticMapImagePath(cursor.getString(cursor.getColumnIndex(SkirunMetadata.MAP_IMG)));
    }
    skirun.setMeteoURL(cursor.getString(cursor.getColumnIndex(SkirunMetadata.METEO_URL)));
    skirun.setName(cursor.getString(cursor.getColumnIndex(SkirunMetadata.NAME)));
    skirun.setNightmode(cursor.getInt(cursor.getColumnIndex(SkirunMetadata.NIGHTMODE)) == 1 ? true : false);
    skirun.setRemoteURL(cursor.getString(cursor.getColumnIndex(SkirunMetadata.REMOTE_URL)));
    skirun.setSchedule(cursor.getString(cursor.getColumnIndex(SkirunMetadata.SCHEDULE)));
    try {
      skirun.setSkirunStatus(SkirunStatus.valueOf(cursor.getString(cursor.getColumnIndex(SkirunMetadata.SKIRUNSTATUS))));
    }
    catch (Exception e) {

    }
    String skiTransportsStr = cursor.getString(cursor.getColumnIndex(SkirunMetadata.SKI_TRANSPORTS));
    try {
      if (skiTransportsStr != null && skiTransportsStr.length() > 0) {
        StringTokenizer tokenizer = new StringTokenizer(skiTransportsStr, "|");
        MessageFormat format = new MessageFormat("{0}x{1}");
        Map<SkiTransport, Integer> skiTransports = new HashMap<SkiTransport, Integer>();
        while (tokenizer.hasMoreTokens()) {
          String token = tokenizer.nextToken();
          Object parsedInfo[] = format.parse(token);
          skiTransports.put(SkiTransport.valueOf((String) parsedInfo[1]), Integer.parseInt((String) parsedInfo[0]));
        }
        skirun.setSkiTransports(skiTransports);
      }
    }
    catch (Exception e) {

    }
    skirun.setDownloaded(cursor.getInt(cursor.getColumnIndex(SkirunMetadata.LOADED)) == 1);
    skirun.setSnowHeight(cursor.getDouble(cursor.getColumnIndex(SkirunMetadata.SNOW_HEIGHT)));
    skirun.setStarred(cursor.getInt(cursor.getColumnIndex(SkirunMetadata.STARRED)) == 1);
    skirun.setStartingAltitude(cursor.getDouble(cursor.getColumnIndex(SkirunMetadata.STARTING_ALT)));
    skirun.setUpdated(new Date(cursor.getLong(cursor.getColumnIndex(SkirunMetadata.UPDATED))));
    skirun.setWidth(cursor.getDouble(cursor.getColumnIndex(SkirunMetadata.WIDTH)));
    skirun.setObservations(cursor.getString(cursor.getColumnIndex(SkirunMetadata.OBSERVATIONS)));
    return skirun;
  }

}
